/**
 *
 */
package de.cbf.cam.dsa.services.impl.rcp_provider.extension;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SafeRunner;
import org.osgi.framework.BundleContext;

import de.cbf.cam.dsa.services.impl.rcp_provider.extension.interfaces.IRCPPersisterCulture;
import de.cbf.cam.dsa.services.impl.rcp_provider.extension.interfaces.IRCPPersisterProfession;
import de.cbf.cam.dsa.services.impl.rcp_provider.extension.interfaces.IRCPPersisterRace;
import de.cbf.cam.dsa.services.impl.rcp_provider.extension.interfaces.IRCPPersisterStructure;

/**
 * @author salter
 *
 */
public class RCPServiceImplExtensionPointResovler {
	private static final Log logger = LogFactory.getLog(RCPServiceImplExtensionPointResovler.class);

	private static final String EXTENSION_POINT_RACE_PERSISTER_ID 		= "de.cbf.cam.dsa.rcp.persistence.race";
	private static final String EXTENSION_POINT_CULTURE_PERSISTER_ID 	= "de.cbf.cam.dsa.rcp.persistence.culture";
	private static final String EXTENSION_POINT_PROFESSION_PERSISTER_ID = "de.cbf.cam.dsa.rcp.persistence.profession";
	private static final String EXTENSION_POINT_STRUCTURE_PERSISTER_ID	= "de.cbf.cam.dsa.rcp.persistence.structure";

	protected static RCPServiceImplExtensionPointResovler instance;

	protected BundleContext fBundleContext;

	protected Map<String,IRCPPersisterRace>			racePersistersMap;
	protected Map<String,IRCPPersisterCulture> 		culturePersistersMap;
	protected Map<String,IRCPPersisterProfession> 	professionPersistersMap;
	protected Map<String,IRCPPersisterStructure> 	structurePersistersMap;

	protected String preferredRacePersister			= null;
	protected String preferredCulturePersister		= null;
	protected String preferredProfessionPersister	= null;
	protected String preferredStructurePersister	= null;

	public static RCPServiceImplExtensionPointResovler getInstance() {
		if(instance == null){
			instance = new RCPServiceImplExtensionPointResovler();
		}
		return instance;
	}

	private RCPServiceImplExtensionPointResovler() {
		super();
		racePersistersMap 		= new HashMap<String, IRCPPersisterRace>();
		culturePersistersMap 	= new HashMap<String, IRCPPersisterCulture>();
		professionPersistersMap	= new HashMap<String, IRCPPersisterProfession>();
		structurePersistersMap	= new HashMap<String, IRCPPersisterStructure>();
	}

	public void setBundleContext(BundleContext context) {
		this.fBundleContext = context;
		evaluateExtensions();
	}

	protected void evaluateExtensions() {
		logger.debug("evaluating extensions...");
		evaluateRacePersisters();
		evaluateCulturePersisters();
		evaluateProfessionPersisters();
		evaluateStructurePersisters();
		logger.debug("evaluating extensions finished");
	}

	protected void evaluateRacePersisters() {
		logger.trace("Evaluating race persister extensions");
		//
		IConfigurationElement[] elements =  Platform.getExtensionRegistry().
		  getConfigurationElementsFor(EXTENSION_POINT_RACE_PERSISTER_ID);

		try {
			for (IConfigurationElement e : elements) {
		  		logger.trace("Evaluating race persister extension: "+e);

		        final Object object = e.createExecutableExtension("class");
		        if(object == null){
		        	logger.error("ExecutableExtension not created, check IExecutableExtensionFactory implementation for create()");
		        }
		        if (object instanceof IRCPPersisterRace) {
		        	IRCPPersisterRace persister = (IRCPPersisterRace)object;
		        	executeRacePersisterExtension(persister);
		        }else{
					logger.error( "Wrong class of object returned("+object.getClass().getName()+"),/n" +
		        			"would need "+IRCPPersisterRace.class.getName());
		        }
			}
		} catch (CoreException ex) {
			logger.error(ex.getMessage());
		}
	}


	protected void evaluateCulturePersisters() {
		logger.trace("Evaluating culture persister extensions");
		//
		IConfigurationElement[] elements =  Platform.getExtensionRegistry().
		  getConfigurationElementsFor(EXTENSION_POINT_CULTURE_PERSISTER_ID);

		try {
			for (IConfigurationElement e : elements) {
		  		logger.trace("Evaluating culture persister extension: "+e);

		        final Object object = e.createExecutableExtension("class");
		        if(object == null){
		        	logger.error("ExecutableExtension not created, check IExecutableExtensionFactory implementation for create()");
		        }
		        if (object instanceof IRCPPersisterCulture) {
		        	IRCPPersisterCulture persister = (IRCPPersisterCulture)object;
		        	executeCulturePersisterExtension(persister);
		        }else{
					logger.error( "Wrong class of object returned("+object.getClass().getName()+"),/n" +
		        			"would need "+IRCPPersisterCulture.class.getName());
		        }
			}
		} catch (CoreException ex) {
			logger.error(ex.getMessage());
		}
	}

	protected void evaluateProfessionPersisters() {
		logger.trace("Evaluating profession persister extensions");
		//
		IConfigurationElement[] elements =  Platform.getExtensionRegistry().
		  getConfigurationElementsFor(EXTENSION_POINT_PROFESSION_PERSISTER_ID);

		try {
			for (IConfigurationElement e : elements) {
		  		logger.trace("Evaluating profession persister extension: "+e);

		        final Object object = e.createExecutableExtension("class");
		        if(object == null){
		        	logger.error("ExecutableExtension not created, check IExecutableExtensionFactory implementation for create()");
		        }
		        if (object instanceof IRCPPersisterProfession) {
		        	IRCPPersisterProfession persister = (IRCPPersisterProfession)object;
		        	executeProfessionPersisterExtension(persister);
		        }else{
					logger.error( "Wrong class of object returned("+object.getClass().getName()+"),/n" +
		        			"would need "+IRCPPersisterProfession.class.getName());
		        }
			}
		} catch (CoreException ex) {
			logger.error(ex.getMessage());
		}
	}

	protected void evaluateStructurePersisters() {
		logger.trace("Evaluating structure persister extensions");
		//
		IConfigurationElement[] elements =  Platform.getExtensionRegistry().
		  getConfigurationElementsFor(EXTENSION_POINT_STRUCTURE_PERSISTER_ID);

		try {
			for (IConfigurationElement e : elements) {
		  		logger.trace("Evaluating structure persister extension: "+e);

		        final Object object = e.createExecutableExtension("class");
		        if(object == null){
		        	logger.error("ExecutableExtension not created, check IExecutableExtensionFactory implementation for create()");
		        }
		        if (object instanceof IRCPPersisterStructure) {
		        	IRCPPersisterStructure persister = (IRCPPersisterStructure)object;
		        	executeStructurePersisterExtension(persister);
		        }else{
					logger.error( "Wrong class of object returned("+object.getClass().getName()+"),/n" +
		        			"would need "+IRCPPersisterStructure.class.getName());
		        }
			}
		} catch (CoreException ex) {
			logger.error(ex.getMessage(),ex);
		}
	}
	protected void executeRacePersisterExtension(final IRCPPersisterRace persister) {
	    ISafeRunnable runnable = new ISafeRunnable() {
	    	@Override
	    	public void handleException(Throwable e) {
	    		logger.error("Exception in running extension");
	    	}

	    	@Override
	    	public void run() throws Exception {
	    		addRacePersister(persister);
	    	}
	    };
	    SafeRunner.run(runnable);
	}
	protected void executeCulturePersisterExtension(final IRCPPersisterCulture persister) {
	    ISafeRunnable runnable = new ISafeRunnable() {
	    	@Override
	    	public void handleException(Throwable e) {
	    		logger.error("Exception in running extension");
	    	}

	    	@Override
	    	public void run() throws Exception {
	    		addCulturePersister(persister);
	    	}
	    };
	    SafeRunner.run(runnable);
	}
	protected void executeProfessionPersisterExtension(final IRCPPersisterProfession persister) {
	    ISafeRunnable runnable = new ISafeRunnable() {
	    	@Override
	    	public void handleException(Throwable e) {
	    		logger.error("Exception in running extension");
	    	}

	    	@Override
	    	public void run() throws Exception {
	    		addProfessionPersister(persister);
	    	}
	    };
	    SafeRunner.run(runnable);
	}
	protected void executeStructurePersisterExtension(final IRCPPersisterStructure persister) {
	    ISafeRunnable runnable = new ISafeRunnable() {
	    	@Override
	    	public void handleException(Throwable e) {
	    		logger.error("Exception in running extension");
	    	}

	    	@Override
	    	public void run() throws Exception {
	    		addStructurePersister(persister);
	    	}
	    };
	    SafeRunner.run(runnable);
	}

	public void addRacePersister(IRCPPersisterRace persister) {
		if(racePersistersMap.isEmpty()){
			preferredRacePersister = persister.getName();//choose first as preferred if empty
		}
		racePersistersMap.put(persister.getName(), persister);
	}

	public void addCulturePersister(IRCPPersisterCulture persister) {
		if(culturePersistersMap.isEmpty()){
			preferredCulturePersister = persister.getName();//choose first as preferred if empty
		}
		culturePersistersMap.put(persister.getName(), persister);
	}
	public void addProfessionPersister(IRCPPersisterProfession persister) {
		if(professionPersistersMap.isEmpty()){
			preferredProfessionPersister = persister.getName();//choose first as preferred if empty
		}
		professionPersistersMap.put(persister.getName(), persister);
	}
	public void addStructurePersister(IRCPPersisterStructure persister) {
		if(structurePersistersMap.isEmpty()){
			preferredStructurePersister = persister.getName();//choose first as preferred if empty
		}
		structurePersistersMap.put(persister.getName(), persister);
	}

	public Set<String> getRegisteredRacePersisters(){
		return racePersistersMap.keySet();
	}

	public IRCPPersisterRace getRacePersister(String name) {
		return racePersistersMap.get(name);
	}

	public IRCPPersisterRace getPreferredRacePersister() {
		return racePersistersMap.get(preferredRacePersister);
	}

	public void setPreferredRacePersister(String preferredRacePersister) {
		if(racePersistersMap.get(preferredRacePersister)!= null){
			this.preferredRacePersister = preferredRacePersister;
		}else{
			logger.error("RacePersister not existant: "+preferredRacePersister );
		}
	}

	public Set<String> getRegisteredCulturePersisters(){
		return culturePersistersMap.keySet();
	}

	public IRCPPersisterCulture getCulturePersister(String name) {
		return culturePersistersMap.get(name);
	}

	public IRCPPersisterCulture getPreferredCulturePersister() {
		return culturePersistersMap.get(preferredCulturePersister);
	}

	public void setPreferredCulturePersister(String preferredCulturePersister) {
		if(culturePersistersMap.get(preferredCulturePersister)!= null){
			this.preferredCulturePersister = preferredCulturePersister;
		}else{
			logger.error("CulturePersister not existant: "+preferredCulturePersister );
		}
	}

	public Set<String> getRegisteredProfessionPersisters(){
		return professionPersistersMap.keySet();
	}

	public IRCPPersisterProfession getProfessionPersister(String name) {
		return professionPersistersMap.get(name);
	}

	public IRCPPersisterProfession getPreferredProfessionPersister() {
		return professionPersistersMap.get(preferredProfessionPersister);
	}

	public void setPreferredProfessionPersister(String preferredProfessionPersister) {
		if(professionPersistersMap.get(preferredProfessionPersister)!= null){
			this.preferredProfessionPersister = preferredProfessionPersister;
		}else{
			logger.error("ProfessionPersister not existant: "+preferredProfessionPersister );
		}
	}

	public Set<String> getRegisteredStructurePersisters(){
		return structurePersistersMap.keySet();
	}

	public IRCPPersisterStructure getStructurePersister(String name) {
		return structurePersistersMap.get(name);
	}

	public IRCPPersisterStructure getPreferredStructurePersister() {
		return structurePersistersMap.get(preferredStructurePersister);
	}

	public void setPreferredStructurePersister(String preferredStructurePersister) {
		if(structurePersistersMap.get(preferredStructurePersister)!= null){
			this.preferredStructurePersister = preferredStructurePersister;
		}else{
			logger.error("StructurePersister not existant: "+preferredStructurePersister );
		}
	}
}
